using System;
using Gizmox.WebGUI.Common.Resources;
using Gizmox.WebGUI.Forms;
using VisualDB.Entities;
using VisualDB.DAL;
using System.Collections.Generic;

namespace VisualDB.Helpers
{
    public class PresentationLayer
    {
        private static PresentationLayer _instance;
        private MainForm _mainForm;

        public static PresentationLayer Instance
        {
            get
            {
                if (_instance == null)
                    _instance = new PresentationLayer();

                return _instance;
            }
        }

        public TreeView TreeViewDatabaseObjects
        {
            get
            {
                return _mainForm.trvObjects;
            }
        }

        private TabControl TabControl
        {
            get
            {
                return _mainForm.tabControl;
            }
        }

        private ToolBar MainToolBar
        {
            get
            {
                return _mainForm.mainToolBar;
            }
        }

        public void SetMainForm(MainForm mainForm)
        {
            _mainForm = mainForm;
        }

        public void FillTreeViewDatabaseObjects()
        {
            TreeNode databasesNode = new TreeNode("Databases");
            databasesNode.Image = new ImageResourceHandle("Images.Databases.gif");
            databasesNode.Tag = "Databases";
            TreeViewDatabaseObjects.Nodes.Add(databasesNode);

            foreach (DatabaseEntity database in ConfigurationHelper.Instance.GetRegisteredDatabases())
            {
                TreeNode databaseNode = new TreeNode(database.Name);
                databaseNode.Image = new ImageResourceHandle("Images.DatabaseDisconnected.gif");

                IDatabaseDAL databaseDAL = DALFactory.GetDatabaseDAL(database);
                databaseDAL.DatabaseEntity.DatabaseName = database.DatabaseName;

                databaseNode.Tag = databaseDAL;
                databaseNode.HasNodes = true;
                databaseNode.Loaded = false;
                databaseNode.IsExpanded = false;

                TreeViewDatabaseObjects.Nodes[0].Nodes.Add(databaseNode);
            }

            this.TreeViewDatabaseObjects.SelectedNode = databasesNode;
        }

        public void FillTreeViewDatabaseChilds(TreeNode databaseNode)
        {
            TreeNode tablesNode = new TreeNode("Tables");
            tablesNode.Image = new ImageResourceHandle("Images.Tables.gif");
            tablesNode.Tag = "Tables";
            tablesNode.HasNodes = true;
            tablesNode.Loaded = false;
            tablesNode.IsExpanded = false;

            TreeNode viewsNode = new TreeNode("Views");
            viewsNode.Image = new ImageResourceHandle("Images.Views.gif");
            viewsNode.Tag = "Views";
            viewsNode.HasNodes = true;
            viewsNode.Loaded = false;
            viewsNode.IsExpanded = false;

            TreeNode storedProceduresNode = new TreeNode("Stored Procedures");
            storedProceduresNode.Image = new ImageResourceHandle("Images.StoredProcedures.gif");
            storedProceduresNode.Tag = "StoredProcedures";
            storedProceduresNode.HasNodes = true;
            storedProceduresNode.Loaded = false;
            storedProceduresNode.IsExpanded = false;

            databaseNode.Nodes.Add(tablesNode);
            databaseNode.Nodes.Add(viewsNode);
            databaseNode.Nodes.Add(storedProceduresNode);

            databaseNode.Loaded = true;
        }

        public void FillTreeViewTableViewChilds(TreeNode tableViewNode)
        {
            IDatabaseDAL databaseDAL = (IDatabaseDAL)tableViewNode.Parent.Parent.Tag;

            List<ColumnEntity> columns;

            if (tableViewNode.Tag is TableEntity)
            {
                TableEntity table = (TableEntity)tableViewNode.Tag;
                columns = databaseDAL.GetColumns(table);
            }
            else
            {
                ViewEntity view = (ViewEntity)tableViewNode.Tag;
                columns = databaseDAL.GetColumns(view);
            }

            foreach (ColumnEntity column in columns)
            {
                TreeNode columnNode = new TreeNode(string.Format("{0} {1}", column.Name, column.Type));

                if (column.PrimaryKey)
                    columnNode.Image = new ImageResourceHandle("Images.ColumnPrimaryKey.gif");
                else
                    columnNode.Image = new ImageResourceHandle("Images.Column.gif");

                columnNode.Tag = tableViewNode;

                tableViewNode.Nodes.Add(columnNode);
            }

            tableViewNode.Loaded = true;
        }

        public void ConnectDatabase(TreeNode databaseNode, bool expand)
        {
            IDatabaseDAL databaseDAL = (IDatabaseDAL)databaseNode.Tag;
            databaseDAL.Open();
            databaseNode.Image = new ImageResourceHandle("Images.DatabaseConnected.gif");

            if (expand)
                databaseNode.Expand();

            TreeViewDatabaseObjects.Update();
        }

        public void DisconnectDatabase(TreeNode databaseNode)
        {
            IDatabaseDAL databaseDAL = (IDatabaseDAL)databaseNode.Tag;
            databaseDAL.Close();
            databaseNode.Image = new ImageResourceHandle("Images.DatabaseDisconnected.gif");
            databaseNode.Collapse();
            TreeViewDatabaseObjects.Update();
        }

        public void UpdateUIOnNodeChanged(TreeNode node)
        {
            FindButtonByName("btnNewQuery").Enabled = false;

            if (node.Tag is string)
            {
                switch (node.Tag.ToString())
                {
                    case "Databases":
                        TreeViewDatabaseObjects.ContextMenu = _mainForm.contextMenuDatabases;
                        break;

                    case "Tables":
                        TreeViewDatabaseObjects.ContextMenu = _mainForm.contextMenuTables;
                        break;

                    case "Views":
                        TreeViewDatabaseObjects.ContextMenu = _mainForm.contextMenuViews;
                        break;

                    case "StoredProcedures":
                        TreeViewDatabaseObjects.ContextMenu = _mainForm.contextMenuStoredProcedures;
                        break;

                    default:
                        TreeViewDatabaseObjects.ContextMenu = null;
                        break;
                }
            }
            else if (node.Tag is IDatabaseDAL)
            {
                TreeViewDatabaseObjects.ContextMenu = _mainForm.contextMenuDatabase;
                FindButtonByName("btnNewQuery").Enabled = true;
            }
            else if (node.Tag is TableEntity)
            {
                TreeViewDatabaseObjects.ContextMenu = _mainForm.contextMenuTable;
            }
            else if (node.Tag is ViewEntity)
            {
                TreeViewDatabaseObjects.ContextMenu = _mainForm.contextMenuView;
            }
            else if (node.Tag is StoredProcedureEntity)
            {
                TreeViewDatabaseObjects.ContextMenu = _mainForm.contextMenuStoredProcedure;
            }
            else
            {
                TreeViewDatabaseObjects.ContextMenu = null;
            }
        }

        public void UpdateUIOnTabChanged()
        {

        }

        private ToolBarButton FindButtonByName(string name)
        {
            foreach (ToolBarButton button in this.MainToolBar.Buttons)
            {
                if (button.Name == name)
                {
                    return button;
                }
            }

            return null;
        }

        public void FillNodeOnExpand(TreeNode node)
        {
            if (node.Tag is IDatabaseDAL)
            {
                IDatabaseDAL databaseDAL = (IDatabaseDAL)node.Tag;

                if (!databaseDAL.IsOpened)
                {
                    PresentationLayer.Instance.ConnectDatabase(node, false);
                }
            }

            if (!node.Loaded)
            {
                if (node.Tag is IDatabaseDAL)
                {
                    PresentationLayer.Instance.FillTreeViewDatabaseChilds(node);
                }
                else if (node.Tag is TableEntity || node.Tag is ViewEntity)
                {
                    PresentationLayer.Instance.FillTreeViewTableViewChilds(node);
                }
                else if (node.Tag is string)
                {
                    IDatabaseDAL databaseDAL;

                    switch (node.Tag.ToString())
                    {
                        case "Tables":
                            databaseDAL = (IDatabaseDAL)node.Parent.Tag;

                            List<TableEntity> tables = databaseDAL.GetTables();

                            foreach (TableEntity table in tables)
                            {
                                TreeNode tableNode = new TreeNode(table.Name);
                                tableNode.Image = new ImageResourceHandle("Images.Table.gif");
                                tableNode.Tag = table;
                                tableNode.HasNodes = true;
                                tableNode.Loaded = false;
                                tableNode.IsExpanded = false;

                                node.Nodes.Add(tableNode);
                            }

                            node.Loaded = true;

                            break;

                        case "Views":
                            databaseDAL = (IDatabaseDAL)node.Parent.Tag;

                            List<ViewEntity> views = databaseDAL.GetViews();

                            foreach (ViewEntity view in views)
                            {
                                TreeNode viewNode = new TreeNode(view.Name);
                                viewNode.Image = new ImageResourceHandle("Images.View.gif");
                                viewNode.Tag = view;
                                viewNode.HasNodes = true;
                                viewNode.Loaded = false;
                                viewNode.IsExpanded = false;

                                node.Nodes.Add(viewNode);
                            }

                            node.Loaded = true;

                            break;

                        case "StoredProcedures":
                            databaseDAL = (IDatabaseDAL)node.Parent.Tag;

                            List<StoredProcedureEntity> storedProcedures = databaseDAL.GetStoredProcedures();

                            foreach (StoredProcedureEntity storedProcedure in storedProcedures)
                            {
                                TreeNode storedProcedureNode = new TreeNode(storedProcedure.Name);
                                storedProcedureNode.Image = new ImageResourceHandle("Images.StoredProcedure.gif");
                                storedProcedureNode.Tag = storedProcedure;

                                node.Nodes.Add(storedProcedureNode);
                            }

                            node.Loaded = true;

                            break;
                    }
                }
            }
        }

        public void NewQuery()
        {
            PresentationLayer.Instance.ConnectDatabase(this.TreeViewDatabaseObjects.SelectedNode, true);
            IDatabaseDAL databaseDAL = (IDatabaseDAL)this.TreeViewDatabaseObjects.SelectedNode.Tag;

            NewQuery(databaseDAL, "");
        }

        public void NewQuery(IDatabaseDAL databaseDAL, string query)
        {
            TabPage pageQuery = new TabPage(string.Format("Query ({0})", databaseDAL.DatabaseEntity.Name));
            QueryUC queryUC = new QueryUC(databaseDAL, query);
            queryUC.Dock = DockStyle.Fill;
            pageQuery.Controls.Add(queryUC);
            this.TabControl.SelectedIndex = this.TabControl.TabPages.Add(pageQuery);
        }

        public void NewQueryGenerateScript(ScriptType scriptType)
        {
            IDatabaseDAL databaseDAL;

            ViewEntity view;
            StoredProcedureEntity storedProcedure;

            string query;

            switch (scriptType)
            {
                case ScriptType.NewView:
                    databaseDAL = (IDatabaseDAL)this.TreeViewDatabaseObjects.SelectedNode.Parent.Tag;
                    view = new ViewEntity();
                    view.Name = "NewView";
                    query = databaseDAL.GenerateScriptAddEditView(view, true);
                    break;

                case ScriptType.EditView:
                    databaseDAL = (IDatabaseDAL)this.TreeViewDatabaseObjects.SelectedNode.Parent.Parent.Tag;
                    view = (ViewEntity)this.TreeViewDatabaseObjects.SelectedNode.Tag;
                    query = databaseDAL.GenerateScriptAddEditView(view, false);
                    break;

                case ScriptType.SelectView:
                    databaseDAL = (IDatabaseDAL)this.TreeViewDatabaseObjects.SelectedNode.Parent.Parent.Tag;
                    view = (ViewEntity)this.TreeViewDatabaseObjects.SelectedNode.Tag;
                    query = databaseDAL.GenerateScriptSelectView(view);
                    break;

                case ScriptType.NewStoredProcedure:
                    databaseDAL = (IDatabaseDAL)this.TreeViewDatabaseObjects.SelectedNode.Parent.Tag;
                    storedProcedure = new StoredProcedureEntity();
                    storedProcedure.Name = "NewStoredProcedure";
                    query = databaseDAL.GenerateScriptAddEditStoredProcedure(storedProcedure, true);
                    break;

                case ScriptType.EditStoredProcedure:
                    databaseDAL = (IDatabaseDAL)this.TreeViewDatabaseObjects.SelectedNode.Parent.Parent.Tag;
                    storedProcedure = (StoredProcedureEntity)this.TreeViewDatabaseObjects.SelectedNode.Tag;
                    query = databaseDAL.GenerateScriptAddEditStoredProcedure(storedProcedure, false);
                    break;

                case ScriptType.ExecuteStoredProcedure:
                    databaseDAL = (IDatabaseDAL)this.TreeViewDatabaseObjects.SelectedNode.Parent.Parent.Tag;
                    storedProcedure = (StoredProcedureEntity)this.TreeViewDatabaseObjects.SelectedNode.Tag;
                    query = databaseDAL.GenerateScriptExecuteStoredProcedure(storedProcedure);
                    break;

                default:
                    databaseDAL = (IDatabaseDAL)this.TreeViewDatabaseObjects.SelectedNode.Parent.Parent.Tag;
                    TableEntity table = (TableEntity)this.TreeViewDatabaseObjects.SelectedNode.Tag;
                    query = databaseDAL.GenerateScriptTable(scriptType, table);
                    break;
            }

            NewQuery(databaseDAL, query);
        }

        public void ExecuteQuery(IDatabaseDAL databaseDAL, string query)
        {
            PreviewQueryForm previewQuery = new PreviewQueryForm(databaseDAL, query);
            previewQuery.ShowDialog(_mainForm);
        }

        public void RenameTable(IDatabaseDAL databaseDAL, string oldName, string newName)
        {
            ExecuteQuery(databaseDAL, databaseDAL.RenameTable(oldName, newName));
        }

        public void DeleteTable(IDatabaseDAL databaseDAL, TableEntity table)
        {
            ExecuteQuery(databaseDAL, databaseDAL.DeleteTable(table));
        }

        public void RenameView(IDatabaseDAL databaseDAL, string oldName, string newName)
        {
            ExecuteQuery(databaseDAL, databaseDAL.RenameView(oldName, newName));
        }

        public void DeleteView(IDatabaseDAL databaseDAL, ViewEntity view)
        {
            ExecuteQuery(databaseDAL, databaseDAL.DeleteView(view));
        }

        public void RenameStoredProcedure(IDatabaseDAL databaseDAL, string oldName, string newName)
        {
            ExecuteQuery(databaseDAL, databaseDAL.RenameStoredProcedure(oldName, newName));
        }

        public void DeleteStoredProcedure(IDatabaseDAL databaseDAL, StoredProcedureEntity storedProcedure)
        {
            ExecuteQuery(databaseDAL, databaseDAL.DeleteStoredProcedure(storedProcedure));
        }
    }
}
